package opensky.dbcache.dbvp.core;

import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserManager;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.create.table.CreateTable;
import net.sf.jsqlparser.statement.delete.Delete;
import net.sf.jsqlparser.statement.drop.Drop;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.merge.Merge;
import net.sf.jsqlparser.statement.replace.Replace;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.truncate.Truncate;
import net.sf.jsqlparser.statement.update.Update;
import net.sf.jsqlparser.util.deparser.ExpressionDeParser;
import net.sf.jsqlparser.util.deparser.SelectDeParser;
import opensky.dbcache.dbvp.api.ErrorMode;
import opensky.dbcache.dbvp.api.FullTableName;
import opensky.dbcache.dbvp.api.SqlvpException;
import opensky.dbcache.dbvp.api.TablePicker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 解析sql语句并提取出所有的schema和table进行规制转换
 *
 * @Author zhenggm
 * @Date 2017/9/21 上午9:49
 */

public class TablePickerImpl implements TablePicker {

    private static Logger logger = LoggerFactory.getLogger(TablePickerImpl.class);

    @Override
    public String pickTable(String sql, ErrorMode mode, Map<String, Object> params) {

        CCJSqlParserManager parser = new CCJSqlParserManager();
        StringBuilder buffer = new StringBuilder();
        try {
            Statement stmt = parser.parse(new StringReader(sql));

            // 查询语句处理
            if (stmt instanceof Select) {
                Select Statement = (Select) stmt;
                logger.debug("解析sql的语句: {} ",Statement.toString());
                //Start of value modification
                ExpressionDeParser expressionDeParser = new ExpressionDeParser();
                SelectDeParser deparser = new DBSelectDeParser(expressionDeParser, buffer, mode, params);
                expressionDeParser.setSelectVisitor(deparser);
                expressionDeParser.setBuffer(buffer);
                Statement.getSelectBody().accept(deparser);
                logger.debug("替换成功，文本为: {} ",buffer.toString());
                return buffer.toString();
            }
            // 插入语句处理
            if (stmt instanceof Insert) {
                Insert Statement = (Insert) stmt;
                logger.debug("解析sql的语句: {} ",Statement.toString());
                String schema = Statement.getTable().getSchemaName();
                String table = Statement.getTable().getName();
                FullTableName ftb = new FullTableName(schema, table);
                TableChangerImpl tableChanger = new TableChangerImpl(mode);
                ftb = tableChanger.change(ftb, params);
                Table t = new Table();
                t.setSchemaName(ftb.getSchema());
                t.setName(ftb.getTable());
                Statement.setTable(t);

                // 获取insert语句中的查询语句，如果没有则不替换select
                Select select = Statement.getSelect();
                if (select != null) {
                    ExpressionDeParser expressionDeParser = new ExpressionDeParser();
                    SelectDeParser deparser = new DBSelectDeParser(expressionDeParser, buffer, mode, params);
                    expressionDeParser.setSelectVisitor(deparser);
                    expressionDeParser.setBuffer(buffer);
                    select.getSelectBody().accept(deparser);
                }
                logger.debug("替换成功，文本为: {} ",Statement.toString());
                return Statement.toString();
            }
            // 更新语句
            if (stmt instanceof Update) {
                Update Statement = (Update) stmt;
                logger.debug("解析sql的语句: {} ",Statement.toString());
                List<Table> update_table = Statement.getTables();
                List<String> str_table = new ArrayList<String>();
                List<Table> new_table = new ArrayList<>();
                // 遍历update中的所有table。
                update_table.forEach(T -> {
                    FullTableName ftb = new FullTableName(T.getSchemaName(), T.getName());
                    TableChangerImpl tableChanger = new TableChangerImpl(mode);
                    ftb = tableChanger.change(ftb, params);
                    Table t = new Table();
                    t.setSchemaName(ftb.getSchema());
                    t.setName(ftb.getTable());
                    new_table.add(t);
                });
                Statement.setTables(new_table);

                // 获取Update语句中的查询语句，如果没有则不替换select
                Select select = Statement.getSelect();
                if (select != null) {
                    ExpressionDeParser expressionDeParser = new ExpressionDeParser();
                    SelectDeParser deparser = new DBSelectDeParser(expressionDeParser, buffer, mode, params);
                    expressionDeParser.setSelectVisitor(deparser);
                    expressionDeParser.setBuffer(buffer);
                    select.getSelectBody().accept(deparser);
                }
                logger.debug("替换成功，文本为: {} ",Statement.toString());
                return Statement.toString();
            }

            // 处理删除语句
            if (stmt instanceof Delete) {
                Delete Statement = (Delete) stmt;
                logger.debug("解析sql的语句: {} ",Statement.toString());
                String schema = Statement.getTable().getSchemaName();
                String table = Statement.getTable().getName();
                FullTableName ftb = new FullTableName(schema, table);
                TableChangerImpl tableChanger = new TableChangerImpl(mode);
                ftb = tableChanger.change(ftb, params);
                Table t = new Table();
                t.setSchemaName(ftb.getSchema());
                t.setName(ftb.getTable());
                Statement.setTable(t);

                // 跟新where中的查询条件语句
                ExpressionDeParser expressionDeParser = new ExpressionDeParser();
                SelectDeParser deparser = new DBSelectDeParser(expressionDeParser, buffer, mode, params);
                expressionDeParser.setSelectVisitor(deparser);
                expressionDeParser.setBuffer(buffer);
                Statement.getWhere().accept(expressionDeParser);
                logger.debug("替换成功，文本为: {} ",Statement.toString());
                return Statement.toString();
            }

            // TRUNCATE 语句处理
            if (stmt instanceof Truncate) {
                Truncate Statement = (Truncate) stmt;
                logger.debug("解析sql的语句: {} ",Statement.toString());
                String schema = Statement.getTable().getSchemaName();
                String table = Statement.getTable().getName();
                FullTableName ftb = new FullTableName(schema, table);
                TableChangerImpl tableChanger = new TableChangerImpl(mode);
                ftb = tableChanger.change(ftb, params);
                Table t = new Table();
                t.setSchemaName(ftb.getSchema());
                t.setName(ftb.getTable());
                Statement.setTable(t);
                logger.debug("替换成功，文本为: {} ",Statement.toString());
                return Statement.toString();
            }

            // Create 语句处理
            if (stmt instanceof CreateTable) {
                CreateTable Statement = (CreateTable) stmt;
                logger.debug("解析sql的语句: {} ",Statement.toString());
                String schema = Statement.getTable().getSchemaName();
                String table = Statement.getTable().getName();
                FullTableName ftb = new FullTableName(schema, table);
                TableChangerImpl tableChanger = new TableChangerImpl(mode);
                ftb = tableChanger.change(ftb, params);
                Table t = new Table();
                t.setSchemaName(ftb.getSchema());
                t.setName(ftb.getTable());
                Statement.setTable(t);

                // 获取Create语句中的查询语句，如果没有则不替换select
                Select select = Statement.getSelect();
                if (select != null) {
                    ExpressionDeParser expressionDeParser = new ExpressionDeParser();
                    SelectDeParser deparser = new DBSelectDeParser(expressionDeParser, buffer, mode, params);
                    expressionDeParser.setSelectVisitor(deparser);
                    expressionDeParser.setBuffer(buffer);
                    select.getSelectBody().accept(deparser);
                }
                logger.debug("替换成功，文本为: {} ",Statement.toString());
                return Statement.toString();
            }

            // Drop 语句处理
            if (stmt instanceof Drop) {
                Drop Statement = (Drop) stmt;
                logger.debug("解析sql的语句: {} ",Statement.toString());
                String schema = Statement.getName().getSchemaName();
                String table = Statement.getName().getName();
                FullTableName ftb = new FullTableName(schema, table);
                TableChangerImpl tableChanger = new TableChangerImpl(mode);
                ftb = tableChanger.change(ftb, params);
                Table t = new Table();
                t.setSchemaName(ftb.getSchema());
                t.setName(ftb.getTable());
                Statement.setName(t);
                logger.debug("替换成功，文本为: {} ",Statement.toString());
                return Statement.toString();
            }

            // Merge 语句处理
            if (stmt instanceof Merge) {
                Merge Statement = (Merge) stmt;
                logger.debug("解析sql的语句: {} ",Statement.toString());
                String schema = Statement.getTable().getSchemaName();
                String table = Statement.getTable().getName();
                FullTableName ftb = new FullTableName(schema, table);
                TableChangerImpl tableChanger = new TableChangerImpl(mode);
                ftb = tableChanger.change(ftb, params);
                Table t = new Table();
                t.setSchemaName(ftb.getSchema());
                t.setName(ftb.getTable());
                Statement.setTable(t);
                logger.debug("替换成功，文本为: {} ",Statement.toString());
                return Statement.toString();
            }

            // Replace 语句处理
            if (stmt instanceof Replace) {
                Replace Statement = (Replace) stmt;
                logger.debug("解析sql的语句: {} ",Statement.toString());
                String schema = Statement.getTable().getSchemaName();
                String table = Statement.getTable().getName();
                FullTableName ftb = new FullTableName(schema, table);
                TableChangerImpl tableChanger = new TableChangerImpl(mode);
                ftb = tableChanger.change(ftb, params);
                Table t = new Table();
                t.setSchemaName(ftb.getSchema());
                t.setName(ftb.getTable());
                Statement.setTable(t);
                logger.debug("替换成功，文本为: {} ",Statement.toString());
                return Statement.toString();
            }

        } catch (JSQLParserException e) {
            logger.error(e.getMessage());
        }
        // 如果四种条件都不匹配则抛出异常。
        throw new SqlvpException("error sql can not be parse!check your sql!");

    }
}
